/*
 * Copyright (c) 2009, Jan Pastor. All Rights Reserved.
 */

package sk.jp.jitag.model.config;

import java.awt.Rectangle;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.ArrayList;

import com.db4o.config.annotations.Indexed;

import sk.jp.commons.exception.ApplicationException;
import sk.jp.commons.utils.CollectionUtils;
import sk.jp.commons.utils.ExceptionUtils;
import sk.jp.jitag.dao.db4o.BaseEntity;
import sk.jp.jitag.dao.db4o.Column;
import sk.jp.jitag.dao.db4o.Unique;
import sk.jp.jitag.dao.db4o.CascadeOnDelete;

/**
 * Configuration profile.
 */
public class Profile extends BaseEntity implements Cloneable {

    private static final Column _LABEL = new Column("label");
    private static final Column _SCANPERIOD = new Column("scanPeriod");
    private static final Column _LAFCLASS = new Column("lafClass");

    @Indexed
    @Unique
    private String id;

    @Indexed
    @Unique
    private String label;

    private String description = "";
    private List<String> repositoryLocations = createList(0);
    private Integer scanPeriod = null;
    private String lafClass = "javax.swing.plaf.metal.MetalLookAndFeel";
    private String lafTheme = null;
    private Integer windowPositionX = null;
    private Integer windowPositionY = null;
    private Integer windowPositionWidth = null;
    private Integer windowPositionHeight = null;
    @CascadeOnDelete
    private List<Tool> tools = createList(0);
    private Integer zoomWidth = null;
    private Integer zoomHeight = null;
    @CascadeOnDelete
    private List<MediaType> mediaTypes = createList(0);
    private Boolean readOnlyMode = Boolean.FALSE;
    private Boolean modifyJpegFiles = Boolean.TRUE;
    private Long lastScanDate = null;

    //----------------------------------------------------------------------

    public Profile(String label) {
        checkNotNullNotEmpty(_LABEL, label);

        this.id = label.hashCode()+"";
        this.label = label;
    }

    //----------------------------------------------------------------------

    public String getId() {
        return id;
    }

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        checkNotNullNotEmpty(_LABEL, label);

        this.label = label;
    }

    public String getDescription() {
        return description;
    }

    public Profile setDescription(String description) {
        this.description = description != null ? description : "";
        return this;
    }

    public List<String> getRepositoryLocations() {
        return repositoryLocations;
    }

    public Profile addRepositoryLocations(String repositoryLocation) {
        if(!repositoryLocations.contains(repositoryLocation)){
            repositoryLocations.add(repositoryLocation);
        }
        return this;
    }

    /**
     * @return value (seconds) or null if not specified (= no auto rescan).
     */
    public Integer getScanPeriod() {
        return scanPeriod;
    }

    public void setScanPeriod(Integer scanPeriod) {
        if(scanPeriod != null){
            checkMinLen(_SCANPERIOD, scanPeriod, 1);
        }

        this.scanPeriod = scanPeriod;
    }

    public String getLafClass() {
        return lafClass;
    }

    public void setLafClass(String lafClass) {
        checkNotNullNotEmpty(_LAFCLASS, lafClass);

        this.lafClass = lafClass;
    }

    /**
     * @return theme identifier or null if not specified.
     */
    public String getLafTheme() {
        return lafTheme;
    }

    public void setLafTheme(String lafTheme) {
        this.lafTheme = lafTheme;
    }

    /**
     * @return value or null if not specified.
     */
    public Rectangle getWindowPosition() {
        if(CollectionUtils.isAllNotNull(windowPositionX, windowPositionY,
                                        windowPositionWidth, windowPositionHeight)){
            return new Rectangle(windowPositionX, windowPositionY, windowPositionWidth,
                                 windowPositionHeight);
        }else{
            return null;
        }
    }

    public Profile setWindowPosition(Rectangle windowPosition) {
        if(windowPosition == null){
            windowPositionX = null;
            windowPositionY = null;
            windowPositionWidth = null;
            windowPositionHeight = null;
        }else{
            windowPositionX = windowPosition.x;
            windowPositionY = windowPosition.y;
            windowPositionWidth = windowPosition.width;
            windowPositionHeight = windowPosition.height;
        }
        return this;
    }

    public List<Tool> getTools() {
        return tools;
    }

    /**
     * Adds tool to list in profile only if is not already in list (instance equality)
     * @param tool
     * @return
     */
    public Profile addTool(Tool tool) {
        if(!tools.contains(tool)){
            tools.add(tool);
        }
        return this;
    }

    /**
     * @return width or null if not specified.
     */
    public Integer getZoomWidth() {
        return zoomWidth;
    }

    public Profile setZoomWidth(Integer zoomWidth) {
        this.zoomWidth = zoomWidth;
        return this;
    }

    /**
     * @return height or null if not specified.
     */
    public Integer getZoomHeight() {
        return zoomHeight;
    }

    public Profile setZoomHeight(Integer zoomHeight) {
        this.zoomHeight = zoomHeight;
        return this;
    }

    public List<MediaType> getMediaTypes() {
        return mediaTypes;
    }

    /**
     * Returns media type of specified type class, supported by this profile
     * @param mediaTypeClass
     * @return media type or null if this profile not yet has added specified
     * media type.
     */
    public MediaType getMediaType(MediaTypeClass.Items mediaTypeClass) {
        for (MediaType mediaType : mediaTypes) {
            if(mediaType.getTypeClass().getCode().equals(mediaTypeClass.name())){
                return mediaType;
            }
        }
        return null;
    }

    public Profile addMediaType(MediaType mediaType){
        MediaType mt = getMediaType(mediaType.getTypeClass().getTypeClassCode());
        if(mt == null){
            mediaTypes.add(mediaType);
            return this;
        }else{
            throw new ApplicationException("This profile already has media type of given media type class",
                                           null,
                                           ExceptionUtils.paramsToMap("mediaTypeClass",
                                                  mediaType.getTypeClass().getLabel()));
        }
    }

    /**
     * Returns a list of all file formats for all media types.
     * @return a list of all file formats for all media types.
     */
    public List<FileFormat> getFileFormats(){
        List<FileFormat> formats = new ArrayList<FileFormat>();
        for (MediaType mediaType : mediaTypes) {
            formats.addAll(mediaType.getFileFormats());
        }
        return formats;
    }

    /**
     * Returns a list of all configured file extensions for all media types and formats.
     * @return a list of all configured (in this profile) file extensions.
     */
    public Set<String> getFileExtensions(){
        Set<String> extensions = new LinkedHashSet<String>() ;
        for (MediaType mediaType : mediaTypes) {
            for (FileFormat fileFormat : mediaType.getFileFormats()) {
                extensions.addAll(fileFormat.getExtensions());
            }
        }
        return extensions;
    }

    public Boolean isReadOnlyMode() {
        return readOnlyMode;
    }

    public void setReadOnlyMode(Boolean readOnlyMode) {
        this.readOnlyMode = readOnlyMode;
    }

    public Boolean isModifyJpegFiles() {
        return modifyJpegFiles;
    }

    public void setModifyJpegFiles(Boolean modifyJpegFiles) {
        this.modifyJpegFiles = modifyJpegFiles;
    }

    public Long getLastScanDate() {
        return lastScanDate;
    }

    public void setLastScanDate(Long lastScanDate) {
        this.lastScanDate = lastScanDate;
    }

    /**
     * @deprecated  Klonovanie robit asi nejako inak, resp. doimplementovat v ostatnych triedach konfiguracie
     */
    @Override
    public Profile clone() {
        try {
            return (Profile) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new ApplicationException(e);
        }
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder();
        sb.append("Profile");
        sb.append("{id='").append(id).append('\'');
        sb.append(", label='").append(label).append('\'');
        sb.append(", description='").append(description).append('\'');
        sb.append(", repositoryLocations=").append(repositoryLocations);
        sb.append(", scanPeriod=").append(scanPeriod);
        sb.append(", lafClass='").append(lafClass).append('\'');
        sb.append(", lafTheme='").append(lafTheme).append('\'');
        sb.append(", windowPositionX=").append(windowPositionX);
        sb.append(", windowPositionY=").append(windowPositionY);
        sb.append(", windowPositionWidth=").append(windowPositionWidth);
        sb.append(", windowPositionHeight=").append(windowPositionHeight);
        sb.append(", tools=").append(tools);
        sb.append(", zoomWidth=").append(zoomWidth);
        sb.append(", zoomHeight=").append(zoomHeight);
        sb.append(", mediaTypes=").append(mediaTypes);
        sb.append(", readOnlyMode=").append(readOnlyMode);
        sb.append(", modifyJpegFiles=").append(modifyJpegFiles);
        sb.append(", lastScanDate=").append(lastScanDate);
        sb.append('}');
        return sb.toString();
    }

}
